/* Copyright 2020 Huawei Device Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Author: liangkz @ https://harmonyos.51cto.com/column/46
 * Date  : 2022.04.01
 *
 */
#include "unistd.h"     //sleep
#include "hdf_base.h"
#include "hdf_io_service_if.h"

#include "hdf_log.h"  // use HDF_LOGI to print log should include this .h

#undef  LOG_TAG
#undef  LOG_DOMAIN
#define LOG_TAG    "led_red"
#define LOG_DOMAIN 0xD002021

#define LED_SERVICE_NAME "led_service"

#define LED_RED_WRITE        1
#define LED_RED_EVENT_NORMAL  100
#define LED_RED_EVENT_OFF     110
#define LED_RED_EVENT_ON      111

static int SendCmd(struct HdfIoService *serv, int32_t cmd_idx, int32_t led_mode)
{
    int ret = HDF_SUCCESS;
    struct HdfSBuf *sendBuf = HdfSbufObtainDefaultSize();  //default 256Bytes data
    if (sendBuf == NULL) {
        HDF_LOGE("obtain sendBuf NG");
        return HDF_FAILURE;
    }

    struct HdfSBuf *replyBuf = HdfSbufObtainDefaultSize();  //default 256Bytes data
    if (replyBuf == NULL) {
        HDF_LOGE("obtain replyBuf NG");
        ret = HDF_DEV_ERR_NO_MEMORY;
        goto out;
    }

	//write a "int32_t" cmd_idx to sendBuf
    if (!HdfSbufWriteInt32(sendBuf, cmd_idx)) {
        HDF_LOGE("write sendBuf NG");
        ret = HDF_FAILURE;
        goto out;
    }

	//write a "int32_t" led_mode to sendBuf
    if (!HdfSbufWriteInt32(sendBuf, led_mode)) {
        HDF_LOGE("write sendBuf NG");
        ret = HDF_FAILURE;
        goto out;
    }

	HDF_LOGI("SendCmd[cmdIdx:%{public}d]: Dispatch(1:LED_RED_WRITE, mode[%{public}d])", cmd_idx, led_mode);
    //int (*Dispatch)(struct HdfObject *service, int cmdId, struct HdfSBuf *data, struct HdfSBuf *reply);
    ret = serv->dispatcher->Dispatch(&serv->object, LED_RED_WRITE, sendBuf, replyBuf);
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("Dispatch(cmd, sendBuf) to service NG");
        goto out;
    }

	//-----------------------------------
	//driver write a "int32_t" to replyBuf, so here read a "int32_t"
    int32_t result = 0;
    if (!HdfSbufReadInt32(replyBuf, &result)) {
        HDF_LOGE("get result from replyBuf NG");
        ret = HDF_FAILURE;
        goto out;
    }

	//driver write a "string" to replyBuf, so here read a "string"
	const char* replyStr = HdfSbufReadString(replyBuf);

    HDF_LOGI("SendCmd[cmdIdx:%{public}d]: Get reply: result[%{public}d](0-OK,x-NG)+'%{public}s'", cmd_idx, result, replyStr);

out:
    HdfSbufRecycle(sendBuf);
    HdfSbufRecycle(replyBuf);
    return ret;
}

#ifdef OHOS_LITE
static int OnDevEventReceived(void *priv, uint32_t cmdId, struct HdfSBuf *reportBuf)
{
	int32_t reportIdx = 0;
	const char *reportMsg = NULL;

	switch (cmdId)
	{
	case LED_RED_EVENT_NORMAL:
		//driver write a "int32_t" to reportBuf, so here read a "int32_t"
	    if (!HdfSbufReadInt32(reportBuf, &reportIdx)) {
	        HDF_LOGE("get reportIdx from reportBuf NG");
	        return HDF_FAILURE;
	    }

		//driver write a "string" to reportBuf, so here read a "string"
	    reportMsg = HdfSbufReadString(reportBuf);
	    if (reportMsg == NULL) {
	        HDF_LOGE("get reportMsg from reportBuf NG");
	        return HDF_FAILURE;
	    }

		//TODO: respond to this event
	    HDF_LOGI("%{public}s: %{public}s: received: EVENT_NORMAL idx[%{public}d]+'%{public}s'",
	             __func__, (char *)priv, reportIdx, reportMsg);
		break;

	case LED_RED_EVENT_OFF:
		//driver write a "string" to reportBuf, so here read a "string"
	    reportMsg = HdfSbufReadString(reportBuf);
	    if (reportMsg == NULL) {
	        HDF_LOGE("get reportMsg from reportBuf NG");
	        return HDF_FAILURE;
	    }

		//driver write a "int32_t" to reportBuf, so here read a "int32_t"
	    if (!HdfSbufReadInt32(reportBuf, &reportIdx)) {
	        HDF_LOGE("get reportIdx from reportBuf NG");
	        return HDF_FAILURE;
	    }

		//TODO: respond to this event
	    HDF_LOGI("%{public}s: %{public}s: received: EVENT_OFF    idx[%{public}d]+'%{public}s'",
	             __func__, (char *)priv, reportIdx, reportMsg);
		break;

	case LED_RED_EVENT_ON:
		//driver write a "string" to reportBuf, so here read a "string"
	    reportMsg = HdfSbufReadString(reportBuf);
	    if (reportMsg == NULL) {
	        HDF_LOGE("get reportMsg from reportBuf NG");
	        return HDF_FAILURE;
	    }

		//driver write a "int32_t" to reportBuf, so here read a "int32_t"
	    if (!HdfSbufReadInt32(reportBuf, &reportIdx)) {
	        HDF_LOGE("get reportIdx from reportBuf NG");
	        return HDF_FAILURE;
	    }

		//TODO: respond to this event
	    HDF_LOGI("%{public}s: %{public}s: received: EVENT_ON     idx[%{public}d]+'%{public}s'",
	             __func__, (char *)priv, reportIdx, reportMsg);
		break;

	default:
		HDF_LOGI("%{public}s: %{public}s: received: unknown event",
				 __func__, (char *)priv);
		break;
	}

    return HDF_SUCCESS;
}
#endif

int main(int argc, char* argv[])
{
	int32_t cmd_cnt = 30;   //default to send cmd_cnt cmd to driver
	int32_t cmd_idx = 0;
	int32_t led_mod = -1;   //0-Off, 1-On, -1||other-defualt to flip
	if (argc >= 2) {
		if (argv[1][0] == '0')
			led_mod = 0;
		else if (argv[1][0] == '1')
			led_mod = 1;
		else if (argv[1][0] == '9')  //Extra mode
			led_mod = 9;
	}

	HDF_LOGI("[%s] main enter: %{public}d::[0-Off/1-On/9-Extra/x-flip]", LOG_TAG, led_mod);
	usleep(10);

    struct HdfIoService *serv = HdfIoServiceBind(LED_SERVICE_NAME);
    if (serv == NULL) {
        HDF_LOGE("get service %{public}s NG", LED_SERVICE_NAME);
        return HDF_FAILURE;
    }

#ifdef OHOS_LITE
    static struct HdfDevEventlistener listener = {
        .callBack = OnDevEventReceived,
        .priv = "Led_Red_Event"
    };

    if (HdfDeviceRegisterEventListener(serv, &listener) != HDF_SUCCESS) {
        HDF_LOGE("register event listener NG");
        return HDF_FAILURE;
    }
#endif

	switch (led_mod)
	{
	case 0:  // set LED OFF
	case 1:  // set LED ON
	case 9:  // set Extra Mode:flip by driver
		if (HDF_SUCCESS != SendCmd(serv, cmd_idx, led_mod)) {
            HDF_LOGE("SendCmd[cmdIdx:%{public}d] NG", cmd_idx);
            return HDF_FAILURE;
        }
		break;
	default:  // set LED ON/OFF flashing cmd_cnt times
	    while(cmd_idx < cmd_cnt) {
			cmd_idx ++;

			HDF_LOGI("SendCmd[cmdIdx:%{public}d]:----------", cmd_idx);
			if (HDF_SUCCESS != SendCmd(serv, cmd_idx, led_mod)) {
	            HDF_LOGE("SendCmd[cmdIdx:%{public}d] NG", cmd_idx);
	            return HDF_FAILURE;
	        }
			HDF_LOGI("SendCmd[cmdIdx:%{public}d]:++++++++++", cmd_idx);

	        sleep(3);
	    }
	}

#ifdef OHOS_LITE
    if (HdfDeviceUnregisterEventListener(serv, &listener)) {
        HDF_LOGE("unregister listener NG");
        return HDF_FAILURE;
    }
#endif

    HdfIoServiceRecycle(serv);
	HDF_LOGI("[%s] main exit.", LOG_TAG);

    return HDF_SUCCESS;
}
